/**
 * 1、promise 是一个类；传入一个立即执行的函数；resolve, reject的this指向promise
 * 2、异步逻辑 
 * 3、then 方法被多次调用
 * 4、then 链式调用
 * 5、then 不能返回自己promise 循环调用自己
 */
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {

  constructor(executor) {
    // try-catch 解决立即执行函数的异常
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error);
    } 
  }

  status = PENDING;
  value = undefined;
  reason = undefined;
  successCallback = [];
  failCallback = [];

  resolve = (value) => {
    if (this.status !== PENDING) return;
    this.status = FULFILLED;
    this.value = value;

    // 如果有成功的回调，就执行
    // this.successCallback && this.successCallback(this.value);
    while(this.successCallback.length) this.successCallback.shift()();
  }

  reject = (reason) => {
    if (this.status !== PENDING) return;
    this.status = REJECTED;
    this.reason = reason;
    // 如果有失败的回调，就执行
    // this.failCallback && this.failCallback(this.reason);
    while(this.failCallback.length) this.failCallback.shift()();
  }

  then(successCallback, failCallback) {
    // 可选参数
    successCallback = successCallback ? successCallback : value => value;
    // 可选参数
    failCallback = failCallback ? failCallback : reason => { throw reason };
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        // 获取promise2这个值
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            // 捕获 successCallback 这个回调的异常
            reject(error);
          }
        });
      } else if (this.status === REJECTED) {        
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            // 捕获 failCallback 这个回调的异常
            reject(error);
          }
        });
      } else {
        // 等待状态
        // 添加 resolve 回调函数
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
        // 添加 reject 回调函数
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
    })
    return promise2;
  }

  // 返回 promise，可继续then链式调用
  // 不管执行的是 resolve 或 reject  都会执行finally
  // resolve 或者 reject 需要等待cb(回调函数)，执行完毕
  finally(cb) {
    return this.then(value => {
      return MyPromise.resolve(cb()).then(() => value);
    }, reason => {
      return MyPromise.resolve(cb()).then(() => { throw reason });
    });
  }

  // 只执行reject
  catch(failCallback) {
    this.then(undefined, failCallback);
  }

  static resolve(promise) {
    if (promise instanceof MyPromise) return promise;
    return new MyPromise(resolve => resolve(promise))
  }

  // 等待数组所有项执行完毕，再回调
  static all(array) {
    const results = [];
    let index = 0;
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        results[key] = value;
        index++;
        // 等待所有promise异步回调执行完
        if (index === array.length) {
          resolve(results);
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        // 当current是promise时，调用then获取值
        if (current instanceof MyPromise) {
          current.then(value => addData(i, value), reason => reject(reason));
        } else {
          // 当current 是普通值时，直接加入数组中
          addData(i, current);
        }
      }
    });
  }

  // 数组中一项执行完成，就resolve
  static race(array) {
    return new MyPromise((resolve, reject) => {
      array.forEach(current => {
        if (current instanceof MyPromise) {
          current.then(resolve, reject);
        } else {
          resolve(value);
        }
      });
    });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  // 防止自己调用自己，即循环引用
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
  }
  // 如果返回值是Promise，则调用then
  if (x instanceof MyPromise) {
    // x.then(value => resolve(value), reason => reject(reason));
    // 简写
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}

module.exports = MyPromise;